﻿using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Net;
using System.Reflection;
using System.Runtime.Remoting.Contexts;
using System.Text;
using System.Threading.Tasks;
using MainFrame.Common.Interface;
using Newtonsoft.Json.Linq;
using Qianke.Common;

namespace MainFrame.Common
{
    public class LocalHttpServer
    {
        HttpListener httpListener = new HttpListener();

        private IController GetCurrentRequestController(string controllerName)
        {
            var keyName = $"{controllerName}Controller";
            var controllerType = UnityHelper.RegisterTypeArray.GetValue(keyName);
            if (controllerType == null)
                return null;
            var unity = UnityHelper.GetContainer();
            var controller = unity.Resolve(controllerType, null) as IController;
            controller.SetServiceContainer(unity);
            return controller;
        }

        public LocalHttpServer(int port)
        {
            httpListener.AuthenticationSchemes = AuthenticationSchemes.Anonymous;

            httpListener.Prefixes.Add($"http://127.0.0.1:{port}/");

            httpListener.Start();//开启服务
            _ = Task.Run(async () =>
            {
                while (true)
                {
                    try
                    {
                        if (httpListener == null)
                            break;
                        var context = await httpListener.GetContextAsync();
                        _ = Task.Run(() => Dispather(context));
                    }
                    catch (Exception ex)
                    {
                        await Task.Delay(1000);
                    }
                }
            });
        }


        private async Task<ReturnInfo> HandleData(string controllerName, string actionName, HttpListenerRequest request)
        {
            try
            {
                if (string.IsNullOrEmpty(controllerName))
                    controllerName = "Home";
                if (string.IsNullOrEmpty(actionName))
                    actionName = "Index";
                var controller = GetCurrentRequestController(controllerName);
                if (controller == null)
                    return new ReturnInfo("404", $"{controllerName}/{actionName}不存在");
                var requestParam = controller.GetService<HttpRequestParam>();
                requestParam.RequestBody = HttpHelper.GetStreamContent(request.InputStream);
                requestParam.ParamObj = string.IsNullOrEmpty(requestParam.RequestBody) ? new JObject() : requestParam.RequestBody.ToObject<JToken>();

                var actionMethod = controller.GetType().GetMethod(actionName);
                if (actionMethod == null)
                    return new ReturnInfo("404", $"{controllerName}/{actionName}不存在");

                var paramArray = new List<object>();
                var paramTypeArray = actionMethod.GetParameters();
                if (paramTypeArray != null && paramTypeArray.Length > 0)
                {
                    var dict = requestParam.ParamObj.ToObject<Dictionary<string, object>>();
                    foreach (var paramType in paramTypeArray)
                    {
                        if (paramType.ParameterType.IsClass)
                            paramArray.Add(requestParam.ParamObj.ToObject(paramType.ParameterType));
                        else
                        {
                            var paramTypeName = paramType.Name.ToLower();
                            var keyName = dict.Keys.FirstOrDefault(u => u.ToLower() == paramTypeName);
                            paramArray.Add(keyName == null ? paramType.DefaultValue : dict[keyName]);
                        }
                    }
                }
                var result = actionMethod.Invoke(controller, paramArray.ToArray());
                var resultTask = result as Task<ReturnInfo>;
                if (resultTask != null)
                    return await resultTask;
                return result as ReturnInfo;
            }
            catch (Exception ex)
            {
                return new ReturnInfoData("-2", "遇到异常", ex);
            }
        }

        /// <summary>
        /// 解析请求
        /// </summary>
        /// <param name="context"></param>
        private async Task Dispather(HttpListenerContext context)
        {
            HttpListenerRequest request = context.Request;
            HttpListenerResponse response = context.Response;
            response.ContentEncoding = Encoding.UTF8;

            response.Headers.Add("Access-Control-Allow-Headers", "*");
            response.Headers.Add("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, OPTIONS");
            response.Headers.Add("Access-Control-Allow-Origin", "*");
            if (request.HttpMethod == "OPTIONS")
            {
                response.Close();
                return;
            }
            response.Headers.Add("Access-Control-Allow-Headers", "Content-Type");
            response.ContentType = "application/json;charset=UTF-8";
            try
            {
                string action = string.Empty;
                string area = string.Empty;
                if (!string.IsNullOrEmpty(request.RawUrl) && request.RawUrl != "/")
                {
                    var infoArray = request.RawUrl.Split(new string[] { "/" }, StringSplitOptions.RemoveEmptyEntries);
                    if (infoArray.Length == 1) //http://localhost:port/GetVersion
                    {
                        area = infoArray[0];
                        action = "Index";
                    }
                    else if (infoArray.Length == 2)//http://localhost:port/IdentityCard/GetVersion //两段地址
                    {
                        area = infoArray[0];
                        action = infoArray[1];
                    }
                }
                var resultData = await HandleData(area, action, request);
                response.StatusCode = 200;
                var tBuffer = response.ContentEncoding.GetBytes(resultData.ToJson());
                using (var wr = response.OutputStream)
                    await wr.WriteAsync(tBuffer, 0, tBuffer.Length);
            }
            catch (Exception ex)
            {
                var tBuffer = response.ContentEncoding.GetBytes(new ReturnInfoData("500", "遇到异常", ex).ToJson());
                using (var wr = response.OutputStream)
                    await wr.WriteAsync(tBuffer, 0, tBuffer.Length);
            }
            finally
            {
                if (response != null)
                    response.Close();
            }
        }


        public void Close()
        {
            try
            {
                if (httpListener != null)
                {
                    httpListener.Stop();
                    httpListener.Abort();
                    httpListener.Close();
                }
                httpListener = null;
            }
            catch (Exception)
            {

            }

        }
    }
}
